package tinybase.pf;

import java.io.FileDescriptor;

import tinybase.basic.RC;

public class HashTable {
	private int numBuckets;
	private HashEntry[] hashTable;

	/* if the file descriptor , how to parse them to integer */
	private final int Hash(FileDescriptor fd, PageNum pageNum) {
		int hashValue= 0;
		if (fd == null)
			hashValue= pageNum.getPageNum() - 1;
		else
			hashValue= fd.hashCode() + pageNum.getPageNum();
		hashValue = hashValue % numBuckets;
		return hashValue;
		//return pageNum.getPageNum() % numBuckets;
		// return ((Integer.parseInt(fd.toString()) + pageNum.getPageNum()) %
		// numBuckets);
	}

	public HashTable(int numBuckets) {
		this.numBuckets = numBuckets;
		hashTable = new HashEntry[numBuckets];
		for (int i = 0; i < numBuckets; i++)
			hashTable[i] = null;
	}

	public RC find(FileDescriptor fd, PageNum pageNum, Slot slot) {
		int bucket = Hash(fd, pageNum);

		if (bucket < 0) {
			return RC.PF_HASHNOTFOUND;
		}

		for (HashEntry entry = hashTable[bucket]; entry != null; entry = entry.next) {
			/**
			 * For the objects, we should use equals instead of ==. 
			 * zliu 24, May, 2011
			 */
			if (((entry.fd == fd && entry.pageNum == pageNum.getPageNum())) ||
					(entry.fd == null && fd == null && entry.pageNum == pageNum.getPageNum())) {
				slot.setSlotValue(entry.slot);
				return RC.PF_SUCCESS;
			}
		}
		return RC.PF_HASHNOTFOUND;
	}

	public RC insert(FileDescriptor fd, PageNum pageNum, Slot slot) {
		int bucket = Hash(fd, pageNum);

		HashEntry entry;
		for (entry = hashTable[bucket];
			entry != null;
			entry = entry.next) {
			if (entry.fd == fd && entry.pageNum == pageNum.getPageNum()) {
				return RC.PF_HASHPAGEEXIST;
			}
		}
		entry = new HashEntry();
		entry.fd = fd;
		entry.pageNum = pageNum.getPageNum();
		entry.slot = slot.getSlotValue();
		entry.next = hashTable[bucket];
		entry.previous = null;
		if (hashTable[bucket] != null)
			hashTable[bucket].previous = entry;
		hashTable[bucket] = entry;

		return RC.PF_SUCCESS;
	}

	public RC delete(FileDescriptor fd, PageNum pageNum) {
		int bucket = Hash(fd, pageNum);

		HashEntry entry;
		for (entry = hashTable[bucket];
			entry != null;
			entry = entry.next) {
			if (entry.fd == fd && entry.pageNum == pageNum.getPageNum())
				break;
		}

		if (entry == null)
			return RC.PF_HASHNOTFOUND;

		if (entry == hashTable[bucket])
			hashTable[bucket] = entry.next;

		if (entry.previous != null)
			entry.previous.next = entry.next;

		if (entry.next != null)
			entry.next.previous = entry.previous;

		return RC.PF_SUCCESS;
	}
}
